home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 21 / Mac Magazin and MacEasy Magazine CD - Issue 21.iso / Wissenschaft & Technik / yorick12vr1-nofpu folder / include / string.i < prev    next >
Text File  |  1996-02-12  |  11KB  |  343 lines

  1. /*
  2.    STRING.I
  3.    String and related convenience functions.
  4.  
  5.    $Id$
  6.    (Based on routines contributed by Eric Theibaut.)
  7.  */
  8. /*    Copyright (c) 1996.  The Regents of the University of California.
  9.                     All rights reserved.  */
  10.  
  11. /*---------------------------------------------------------------------------
  12.  * @(#) string.i: string manipulation and miscellaneous functions for Yorick
  13.  * @(#)           by Eric THIEBAUT.
  14.  *----------------------------------------------------------------------------
  15.  * History:
  16.  *    02/11/95 by Eric THIEBAUT: added definitions of `scalar()' and
  17.  *        `is_vector()'.
  18.  */
  19.  
  20. /* ------------------------------------------------------------------------ */
  21.  
  22. func gettime(&time)
  23. /* DOCUMENT gettime -- get current time in the form "HH:MM:SS"
  24.  *
  25.  * SYNOPSIS: time= gettime();
  26.  *           gettime, time;
  27.  *
  28.  * HISTORY: October 30, 1995 by Eric THIEBAUT.
  29.  *
  30.  * SEE ALSO: getdate, parsedate, timestamp.
  31.  */
  32. { return (time= strpart(timestamp(), 12:19)); }
  33.  
  34. func getdate(&date)
  35. /* DOCUMENT getdate -- get date of the day in the form "DD/MM/YY"
  36.  *
  37.  * SYNOPSIS: date= getdate();
  38.  *           getdate, date;
  39.  *
  40.  * HISTORY: October 30, 1995 by Eric THIEBAUT.
  41.  *
  42.  * SEE ALSO: gettime, parsedate, timestamp.
  43.  */
  44. {
  45.   local day, month, year;
  46.   parsedate, timestamp(), day, month, year;
  47.   year-= (year>=2000)? 2000 : 1900; 
  48.   return (date= swrite(format="%02d/%02d/%02d", day, month, year));
  49. }
  50.  
  51. func parsedate(timestamp, &day, &month, &year, &hour, &minute, &second)
  52. /* DOCUMENT parsedate -- get numerical version of a timestamp
  53.  *
  54.  * SYNOPSIS: parsedate, timestamp, day,month,year, hour,minute,second;
  55.  *           parsedate(timestamp)
  56.  *
  57.  * HISTORY: October 30, 1995 by Eric THIEBAUT.
  58.  *
  59.  * SEE ALSO: gettime, getdate, timestamp.
  60.  */
  61. {
  62.   dayName= "";
  63.   monthName= "";
  64.   day= year= hour= minute= second= 0;
  65.   sread, timestamp, format="%s%s%d%d:%d:%d%d", dayName, monthName,
  66.     day, hour, minute, second, year;
  67.   month= (monthName == ["Jan", "Feb", "Mar", "Apr",
  68.             "May", "Jun", "Jul", "Aug",
  69.             "Sep", "Oct", "Nov", "Dec"]);
  70.   month= 13 - sum(month(psum));
  71.   return [day, month, year, hour, minute, second];
  72. }
  73.  
  74. /* ------------------------------------------------------------------------ */
  75.  
  76. func strtoupper(s)
  77. /* DOCUMENT strtoupper -- convert a string to upper case letters
  78.  *
  79.  * SYNOPSIS: s2 = strtoupper(s)
  80.  *
  81.  * HISTORY: October 10, 1995 by Eric THIEBAUT.
  82.  *
  83.  * SEE ALSO: strtolower
  84.  */
  85. {
  86.   c1= 'a';  c2= 'z';  dir= -1;  /* parameters for _strcase */
  87.   return _strcloop(s, _strcase);
  88. }
  89.  
  90. func strtolower(s)
  91. /* DOCUMENT strtolower -- convert a string to lower case letters
  92.  *
  93.  * SYNOPSIS: s2 = strtolower(s)
  94.  *
  95.  * HISTORY: October 10, 1995 by Eric THIEBAUT.
  96.  *
  97.  * SEE ALSO: strtoupper
  98.  */
  99. {
  100.   c1= 'A';  c2= 'Z';  dir= +1;  /* parameters for _strcase */
  101.   return _strcloop(s, _strcase);
  102. }
  103.  
  104. func _strcase(s)
  105. {
  106.   /* (DHM) s is string to have case changed */
  107.   if (!s) return s;
  108.   c= *pointer(s);
  109.   if (numberof((i=where(c >= c1))) && numberof((j=where(c(i) <= c2))))
  110.     c(i(j))+= dir*('a'-'A');
  111.   return string(&c);
  112. }
  113.  
  114. func strtrim(s, which, blank=)
  115. /* DOCUMENT strtrim(string)
  116.          or strtrim(string, which)
  117.          or strtrim(string, which, blank=blank)
  118.  
  119.    returns STRING without leading and/or trailing blanks.  If STRING is
  120.    only made of blanks, return "".  If STRING is 0x0, return 0x0.
  121.    If WHICH is 1, trim leading blanks (least expensive).  If WHICH is 2,
  122.    trim trailing blanks (a more costly operation).  If WHICH is 3, (the
  123.    default) trim both leading and trailing blanks.
  124.  
  125.    If STRING is an array of strings, result has same dimensions.
  126.  
  127.    The BLANK keyword is a string constituted by characters considered
  128.    as blanks; by default, BLANK is " \t\n" meaning that spaces,
  129.    tabs, and newlines are discarded.
  130.    In the BLANK string, "^", "]", and "-" are treated specially:
  131.    "]" and "-", if present, should come first in the list to avoid
  132.    special treatment, while "^" should not come first.
  133.  
  134.    SEE ALSO: strtrimleft, strtrimright
  135. */
  136. {
  137.   if (is_void(blank) || !strlen(blank)) blank= " \t\n";
  138.   if (is_void(which)) which= 3;
  139.   blank= "%["+blank+"]";
  140.   return _strcloop(s, _strtrim);
  141. }
  142.  
  143. func _strtrim(s)
  144. {
  145.   if (!s) return s;
  146.   b= e= "";
  147.   if (which&1) sread, s, format=blank, b;
  148.   if (which&2) {
  149.     c= *pointer(s);
  150.     if (numberof(c)<2) return s;
  151.     c(1:-1)= c(-1:1:-1);
  152.     sread, string(&c), format=blank, e;
  153.   }
  154.   return strpart(s, 1+strlen(b):-strlen(e));
  155. }
  156.  
  157. func strchr(s, c, last=)
  158. /* DOCUMENT strchr -- get first/last index of a character in a string 
  159.  *
  160.  * SYNOPSIS: i = strchr(s, c)
  161.  *           i = strchr(s, c, last=1)
  162.  *
  163.  * DIAGNOSTIC: returns 0 if character C is not found in string S.
  164.  *
  165.  * HISTORY: October 27, 1995 by Eric THIEBAUT.
  166.  *
  167.  * SEE ALSO: strmatch
  168.  */
  169. {
  170.   return _strcloop(s, _strchr);
  171. }
  172.  
  173. func _strchr(ss)
  174. {
  175.   /* alter result array data type in _strcloop */
  176.   if (structof(s)==string) s= array(0, dimsof(s));
  177.   ss= *pointer(ss);
  178.   if (numberof((i=where(ss == char(c))))) return (last? i(0) : i(1));
  179.   return 0;
  180. }
  181.  
  182. /* (DHM) On the principal of hiding ugliness, do possible loop
  183.  * on string arrays for several operations here.  */
  184. func _strcloop(ss, operation)
  185. {
  186.   vector= dimsof(ss);
  187.   s= array(string, vector);  /* avoid clobbering original if array */
  188.   vector= vector(1);
  189.   for (i=1 ; i<=numberof(ss) ; ++i) {
  190.     r= operation(ss(i));
  191.     if (vector) s(i)= r;
  192.     else s= r;            /* work around Yorick bug */
  193.   }
  194.   return s;
  195. }
  196.  
  197. /* ------------------------------------------------------------------------ */
  198.  
  199. func reform(x, ..)
  200. /* DOCUMENT reform(x, dimlist)
  201.  *    returns array X reshaped according to dimension list DIMLIST.
  202.  *    In most cases, prefer this to reshape.
  203.  * SEE ALSO: array, dimsof
  204.  */
  205. {
  206.   dims= [0];
  207.   while (more_args()) {
  208.     y= next_arg();
  209.     if (is_void(y)) continue;
  210.     if (!dimsof(y)(1)) y= [1, y];
  211.     n= y(1);
  212.     grow, dims, y(2:1+n);
  213.     dims(1)+= n;
  214.   }
  215.   if (dims(1)) {
  216.     y= array(structof(x), dims);
  217.     y(*)= x(*);   /* will blow up if lengths differ */
  218.   } else {
  219.     if (numberof(x)>1) error, "X longer than specified DIMLIST";
  220.     y= x(1);
  221.   }
  222.   return y;
  223. }
  224.  
  225. func is_scalar(x)
  226. /* DOCUMENT is_scalar(object)
  227.  *    returns 1 if OBJECT is a scalar, else 0.
  228.  * SEE ALSO: is_array, is_func, is_void, is_range, is_struct, is_stream
  229.  */
  230. { return is_array(x) && !dimsof(x)(1); }
  231.  
  232. func is_vector(x)
  233. /* DOCUMENT is_vector(object)
  234.  *    returns 1 if OBJECT is a vector (i.e., OBJECT has a single
  235.  *    dimension), else 0.
  236.  * SEE ALSO: is_array, is_func, is_void, is_range, is_struct, is_stream
  237.  */
  238. { return is_array(x) && dimsof(x)(1)==1; }
  239.  
  240. /* ------------------------------------------------------------------------ */
  241.  
  242. func scalar(x, def, lt=, le=, gt=, ge=, type=, arg=, fn=)
  243. /* DOCUMENT scalar -- get optional scalar parameter
  244.  *
  245.  * PROTOTYPE
  246.  *   x = scalar(xarg, xdef, lt=, le=, gt=, ge=, type=, arg=, fn=);
  247.  *
  248.  * ARGUMENTS
  249.  *   XARG    argument passed to the function.
  250.  *   XDEF    default value for the scalar argument (optional, if not
  251.  *           specified, then it is guessed that the caller must supply the
  252.  *           argument).
  253.  * KEYWORDS
  254.  *   GE=     to be valid, XARG must be >= GE (optional, only one of GT or GE
  255.  *           can be used).
  256.  *   GT=     to be valid, XARG must be >  GT (optional, only one of GT or GE
  257.  *           can be used).
  258.  *   LE=     to be valid, XARG must be <= LE (optional, only one of LT or LE
  259.  *           can be used).
  260.  *   LT=     to be valid, XARG must be <  LT (optional, only one of LT or LE
  261.  *           can be used).
  262.  *   TYPE=   data type of the scalar (optional).
  263.  *   FN=     function name for error messages (optional string).
  264.  *   ARG=    argument name for error messages (optional string).
  265.  *
  266.  * DESCRIPTION
  267.  *   Check XARG and return a scalar value (i.e., either XARG converted to TYPE
  268.  *   if it is not void or XDEF otherwise).  If XARG is not within any specified
  269.  *   bound or if it is not a scalar or if it is void (e.g., not specified) and
  270.  *   there is no default value XDEF, an error message is written out.
  271.  *
  272.  * EXAMPLE
  273.  *   The following function has 2 scalar arguments X and Y, the 1st one is an
  274.  *   integer (of type long) which must be specified and be strictly greater
  275.  *   than 22 while the 2nd default to .5 and must be in [0., 1.]:
  276.  *     func foo(x,y) {
  277.  *         x= scalar(x,     gt=22,        type=long,   fn="foo", arg="X");
  278.  *         y= scalar(y, .5, ge=0., le=1., type=double, fn="foo", arg="Y");
  279.  *         ...
  280.  *     }
  281.  *
  282.  * WARNING
  283.  *   There is no checking of consistency of options.
  284.  *
  285.  * HISTORY: 29 Sept. 1995 by Eric THIEBAUT.  (Modified slightly by DHM)
  286.  */
  287. {
  288.   /* Efficiency note (DHM):
  289.      This is pretty slow no matter what because of the long argument list.
  290.      A faster implementation might be:
  291.        check_range(default_value(x, def), lower, upper, flags)
  292.      since you could optionally perform the various checks.  Of course,
  293.      the total number of arguments for a complete test isn't any smaller,
  294.      and there would be extra overhead in multiple function calls.
  295.      Furthermore, it would be difficult to pass in the "user friendly"
  296.      function and argument name options.  (The names of the routines in
  297.      the current call chain would be a handy thing to make available by
  298.      means of a Yorick builtin function call, as would the ability to
  299.      have the error function "pop up" some number of levels so it left
  300.      the person in dbug mode at the level of the caller of functions
  301.      like this one...  That still leaves the argument name, though in
  302.      principal Yorick can figure that out at runtime, too.)
  303.    */
  304.  
  305.   /* get default x if necessary */
  306.   if (is_void(x)) {
  307.     if (is_void(def)) _scalar_err, 5;
  308.     x= def;
  309.   }
  310.  
  311.   /* check that x is indeed scalar */
  312.   dims= dimsof(x);
  313.   if (is_void(dims) || dims(1)) _scalar_err, 6;
  314.  
  315.   /* convert data type if required (note type could be function too) */
  316.   if (!is_void(type)) x= type(x);
  317.  
  318.   /* check that x is in range */
  319.   if (!is_void(lt) && x>=lt) _scalar_err, 1, lt;
  320.   if (!is_void(le) && x>le) _scalar_err, 2, le;
  321.   if (!is_void(gt) && x<=gt) _scalar_err, 3, gt;
  322.   if (!is_void(ge) && x<ge) _scalar_err, 4, ge;
  323.  
  324.   return x;
  325. }
  326.  
  327. func _scalar_err(oops, value)
  328. {
  329.   if (is_void(fn)) fn= "";
  330.   else fn= fn+": ";
  331.   if (is_void(arg)) arg= "argument";
  332.  
  333.   if (oops==5) {
  334.     error, fn+"no default value for "+arg;
  335.   } else if (oops==6) {
  336.     error, fn+arg+" not a scalar value";
  337.   } else {
  338.     error, fn+arg+" must be "+["<","<=",">",">="](oops)+pr1(value);
  339.   }
  340. }
  341.  
  342. /* ------------------------------------------------------------------------ */
  343.